package com.sakura.demo2.gateway.authentication;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken;
import org.springframework.security.oauth2.server.resource.authentication.JwtReactiveAuthenticationManager;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

/**
 * @Author: zhengcan
 * @Date: 2022/5/15
 * @Description: 网关token认证管理器
 *      重写认证管理器，替换默认的认证管理器JwtReactiveAuthenticationManager
 * @see JwtReactiveAuthenticationManager
 * @Version: 1.0.0 创建
 */
@Slf4j
@Component
public class GatewayJwtTokenAuthenticationManager implements ReactiveAuthenticationManager {

    @Autowired
    private TokenStore tokenStore;

    @Override
    public Mono<Authentication> authenticate(Authentication authentication) {
        return Mono.justOrEmpty(authentication)
                // 判断是否为BearerTokenAuthenticationToken类型的token
                .filter(token -> token instanceof BearerTokenAuthenticationToken)
                .cast(BearerTokenAuthenticationToken.class)
                // 取出token
                .map(BearerTokenAuthenticationToken::getToken)
                .flatMap(accessToken -> {
                    log.info("accessToken is :{}", accessToken);
                    OAuth2AccessToken oAuth2AccessToken;
                    try {
                        oAuth2AccessToken = this.tokenStore.readAccessToken(accessToken);
                    } catch (Exception e) {
                        log.error("readAccessToken异常，e={}", e);
                        return Mono.error(new InvalidTokenException(e.getMessage()));
                    }
                    if (null == oAuth2AccessToken) {
                        return Mono.error(new InvalidTokenException("无效的accessToken！"));
                    } else if (oAuth2AccessToken.isExpired()) {
                        return Mono.error(new InvalidTokenException("accessToken过期失效，请重新获取！"));
                    }
                    // 验证token
                    OAuth2Authentication oAuth2Authentication;
                    try {
                        oAuth2Authentication = this.tokenStore.readAuthentication(accessToken);
                    } catch (Exception e) {
                        log.error("readAuthentication异常，e={}", e);
                        return Mono.error(new InvalidTokenException(e.getMessage()));
                    }
                    if (null == oAuth2Authentication) {
                        return Mono.error(new InvalidTokenException("无效的accessToken！"));
                    } else {
                        return Mono.just(oAuth2Authentication);
                    }
                })
                .cast(Authentication.class);

    }

}
